#pragma once

#include <iostream>
#include <string>
#include <vector>
#include <assert.h>
#include <fstream>
#include <unordered_map>
#include "../Comm/util.hpp"
#include "../Comm/Log.hpp"

namespace ns_model
{
    using namespace ns_util;
    // 一个题目所具体有的属性
    struct Question
    {
        std::string number;    // 题目的编号
        std::string title;     // 题目标题
        std::string grade;     // 题目的难易等级  简单 中等 困难
        int cpu_limit;         // 时间限制
        int mem_limit;         // 内存限制
        std::string desc;      // 题目描述
        std::string head;      // 展现给用户的代码
        std::string tail;      // 测试代码
    };


    // 文件版所有题目列表的文件路径
    const std::string QuesList_Path = "./questions/question_list";
    
    class Model
    {
    private:
        std::unordered_map<std::string, Question> _questions_map;
    public:
        Model()
        {
            assert(LoadQuesList(QuesList_Path));
        }
        // 加载所有题目列表
        bool LoadQuesList(const std::string &ques_list_Path)
        {
            ifstream in(QuesList_Path);
            if (!in.is_open()){
                LOG(FATAL, "加载题库失败，请检查...");
                return false;
            }
            std::string line;
            while (std::getline(in, line))
            {
                std::vector<std::string> tokens;
                StringUtil::Splitstring(line, " ", &tokens);

                // id  title  grade  cpu  mem
                if (tokens.size() != 5){
                    LOG(WARNING, "加载部分题目失败...");
                    continue;
                }

                Question q;
                q.number = tokens[0];
                q.title = tokens[1];
                q.grade = tokens[2];

                q.cpu_limit = std::stoi(tokens[3].c_str());
                q.mem_limit = std::stoi(tokens[4].c_str());

                std::string question_path = "./questions/";
                //"./questions/1"
                question_path += q.number;
                question_path += "/";

                //"./questions/1/question_desc"
                std::string question_desc_path = question_path + "question_desc";
                FileUtil::ReadFile(question_desc_path, &(q.desc), true);

                //"./questions/1/head.hpp"
                std::string question_head_path = question_path + "head.hpp";
                FileUtil::ReadFile(question_head_path, &(q.head), true);

                //"./questions/1/tail.hpp"
                std::string question_tail_path = question_path + "tail.hpp";
                FileUtil::ReadFile(question_tail_path, &(q.tail), true);

                _questions_map.insert({q.number, q});
            }
            
            LOG(INFO, "加载题库成功...");
            in.close();

            return true;
        }
        // 获取所有题目
        bool GetAllQuestions(std::vector<Question> *out)
        {
            if (_questions_map.size() == 0){
                LOG(ERROR, "用户获取题库失败...");
                return false;
            }
            for (auto &e : _questions_map){
                out->push_back(e.second);
            }
            LOG(INFO, "用户获取题库成功...");
            return true;
        }
        // 获取指定题目
        bool GetOneQuestion(const std::string &number, Question *q)
        {
            const auto &iter = _questions_map.find(number);
            if (iter == _questions_map.end()){
                LOG(WARNING, "用户获取单个题目失败...");
                return false;
            }
            *q = iter->second;
            return true;
        }
        ~Model() {}
    };
}